LScript Tutorial #4
Tutorial Page Previous Tutorial

Rail Clone Along A Helix Curve

This tutorial will use the LScript created in the previous tutorial to rail clone an object in the currently-selected foreground layers.

For those of you who are not following tutorials in sequence, here in it's entirety is the final helix coil script created in the previous tutorial:

        @define TOTALPOINTS  12
        @define DEGSTEP      30
        @define HEIGHTINCR   .1

        main
        {
           editbegin();

           thepoint = <.5,0,0>;
           pnt[1] = addpoint(thepoint);

           radius = sqrt((thepoint.x * thepoint.x) + (thepoint.z * thepoint.z));
           degrees = DEGSTEP;

           for(x = 2;x <= TOTALPOINTS;x++)
           {
               thepoint.y += HEIGHTINCR;

               thepoint.x = radius * cos(rad(degrees));
               thepoint.z = radius * sin(rad(degrees));

               pnt[x] = addpoint(thepoint);

               degrees += DEGSTEP;
           }

           addcurve(pnt);

           editend();
        }
The first addition we will make to this existing script is layer selection. Since we will be performing a rail clone operation, we will need to place the rail to be cloned along into an active background layer. However, we cannot arbitrarily place our constructed rail into any layer we wish, because the user may have mesh data residing in that layer. We must utilize LScript's internal layer functions to intelligently select working layers that will prevent the script from damaging or destroying existing mesh data. To accomplish this, we will employ the getemptybg() LScript function:

        @define TOTALPOINTS  12
        @define DEGSTEP      30
        @define HEIGHTINCR   .1

        main
        {
           bglayer = getemptybg();
           ...
           editbegin();

           thepoint = <.5,0,0>;
           pnt[1] = addpoint(thepoint);
           ...
The getemptybg() function returns an array of integer values, each representing an empty background layer. In the current implementation, each can be a value between 1 and 10. If there are no available empty background layers, getemptybg() returns 'nil'1:

        @define TOTALPOINTS  12
        @define DEGSTEP      30
        @define HEIGHTINCR   .1

        main
        {
           bglayer = getemptybg();
           if(bglayer == nil)
           {
               error("Eek!  Cannot find an empty background layer.");
               return;
           }
           ...
           editbegin();

           thepoint = <.5,0,0>;
           pnt[1] = addpoint(thepoint);
           ...
If getemptybg() returns successfully, then we can use the first element in the returned array to place ourselves into a working layer. We do this using the setlayer() LScript command:

        @define TOTALPOINTS  12
        @define DEGSTEP      30
        @define HEIGHTINCR   .1

        main
        {
           bglayer = getemptybg();
           if(bglayer == nil)
           {
               error("Eek!  Cannot find an empty background layer.");
               return;
           }

           setlayer(bglayer[1]);

           editbegin();

           thepoint = <.5,0,0>;
           pnt[1] = addpoint(thepoint);
           ...
While this script code works as expected, we have just introduced a rather discourteous blunder into our script's behavior. The call to setlayer() has set the currently-selected foreground layer to the first empty background we detected, but we have just obliterated the user's layers settings in the process! To make matters worse, we don't remember what they were! Without knowing how to restore the state of the layer selections, we cannot go back and perform our rail clone operation.

Before we go merrily trouncing the user's settings, we need to take steps to remember what they were. That way, the script can courteously clean up after itself. We can get a "snapshot" of the current layer settings by making calls to LScript's fglayers() and bglayers() functions. These functions each return an array of integers that reflect which layers are selected as the active foreground and active background, respectively. Armed with this knowledge, we can re-arrange layer selections to suite our purposes, and then restore the settings to their pre-script selections using setlayer() for foreground layers, and setblayer() for background layers.

        @define TOTALPOINTS  12
        @define DEGSTEP      30
        @define HEIGHTINCR   .1

        main
        {
           bglayer = getemptybg();
           if(bglayer == nil)
           {
               error("Eek!  Cannot find an empty background layer.");
               return;
           }

           fg = fglayers();
           bg = bglayers();

           setlayer(bglayer[1]);

           editbegin();

           thepoint = <.5,0,0>;
           pnt[1] = addpoint(thepoint);
           ...
Our layer selection code is, for the most part, complete. All that remains is to restore the previous layer selections after the rail clone operation is complete.

Now, we will add the last few lines of new script code to complete this rail clone script. After we have created a new curve in the selected background layer, we need to restore the previously-selected foreground layers. At this time, we will not be restoring the previously-selected background layers (if any) because we will need to use the layer containing our helix coil curve as the active background if we wish the rail clone to succeed:

               ... 
               degrees += DEGSTEP;
           }

           addcurve(pnt);

           editend();

           setlayer(fg);
           setblayer(bglayer[1]);
           ...
        }
We then add a call to LScript's railclone() command. The object(s) in the active foreground layer(s) will be cloned along the helix curve we created in the active background layer. The parameters passed to railclone() indicate that we wish to have 12 segments and that each clone should be "o"riented along the curve:

               ... 
               degrees += DEGSTEP;
           }

           addcurve(pnt);

           editend();

           setlayer(fg);
           setblayer(bglayer[1]);

           railclone(12,KNOTS,"o");
           ...
        }
Lastly, we clean up after ourselves by removing the helix curve we created, and restoring the user's original layer selections:

               ... 
               degrees += DEGSTEP;
           }

           addcurve(pnt);

           editend();

           setlayer(fg);
           setblayer(bglayer[1]);

           railclone(12,KNOTS,"o");

           setlayer(bglayer[1]);
           delete();

           setlayer(fg);
           setblayer(bg);
        }
Here is the completed rail clone script:

        @define TOTALPOINTS  12
        @define DEGSTEP      30
        @define HEIGHTINCR   .1

        main
        {
           bglayer = getemptybg();
           if(bglayer == nil)
           {
               error("Eek!  Cannot find an empty background layer.");
               return;
           }

           fg = fglayers();
           bg = bglayers();

           setlayer(bglayer[1]);

           editbegin();

           thepoint = <.5,0,0>;
           pnt[1] = addpoint(thepoint);

           radius = sqrt((thepoint.x * thepoint.x) + (thepoint.z * thepoint.z));
           degrees = DEGSTEP;

           for(x = 2;x <= TOTALPOINTS;x++)
           {
               thepoint.y += HEIGHTINCR;

               thepoint.x = radius * cos(rad(degrees));
               thepoint.z = radius * sin(rad(degrees));

               pnt[x] = addpoint(thepoint);

               degrees += DEGSTEP;
           }

           addcurve(pnt);

           editend();

           setlayer(fg);
           setblayer(bglayer[1]);

           railclone(12,KNOTS,"o");

           setlayer(bglayer[1]);
           delete();

           setlayer(fg);
           setblayer(bg);
        }


1 ... Behavior found in v1.0a (build 292) or higher of the interpreter. Also applies to fglayers(),bglayers(),getempty(), and getemptyfg()


Tutorial Page Previous Tutorial
© 1997 NewTek, Inc.